function mat2create() { return [1, 0, 0, 1]; }
function mat2rotate(out, a, rad) {
  var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
  var s = Math.sin(rad);
  var c = Math.cos(rad);
  out[0] = a0 *  c + a2 * s;
  out[1] = a1 *  c + a3 * s;
  out[2] = a0 * -s + a2 * c;
  out[3] = a1 * -s + a3 * c;
  return out;
}

const extent = 2;

const regl = createREGL({
  extensions: ['ANGLE_instanced_arrays'],
  attributes: {antialias: false},
});

// Instantiate a command for drawing lines
const drawLines = reglLines(regl, {
  vert: `
    precision highp float;

    #pragma lines: attribute vec3 xy;
    #pragma lines: position = getPosition(xy);
    #pragma lines: varying vec2 position = getXY(xy);
    uniform mat2 transform;
    uniform vec2 aspect;
    uniform float scale;
    vec4 getPosition(vec3 xy) {
      return vec4((transform * (xy.xy * scale)) * aspect, 0, 1);
    }
    vec2 getXY(vec3 xy) { return xy.xy; }

    #pragma lines: varying float t = getT(xy);
    float getT(vec3 xy) { return xy.z; }

    // Return the line width from a uniorm
    #pragma lines: width = getWidth();
    uniform lowp float width;
    float getWidth() {
      return width;
    }`,
  frag: `
    precision lowp float;
    varying float t;
    varying vec3 lineCoord;
    varying vec2 position;
    uniform vec3 color;
    uniform vec2 range;
    uniform lowp float width;
    uniform float pixelRatio;
    float linearstep(float a, float b, float x) { return clamp((x - a) / (b - a), 0.0, 1.0); }
    void main () {
      float sdf = width * abs(lineCoord.y);
      float alpha = linearstep(width, width - 1.5, sdf);
      float c = fract(t);
      if (c > 1.0 / 3.0 || alpha < 0.2) discard;
      alpha *= smoothstep(range.x, range.y, length(position)) * 0.8;
      gl_FragColor = vec4(color, alpha);
    }`,

  // Multiply the width by the pixel ratio for consistent width
  uniforms: {
    range: [34 * extent, 29 * extent],
    scale: 0.03 / extent,
    color: regl.prop('color'),
    transform: regl.prop('transform'),
    pixelRatio: regl.context('pixelRatio'),
    width: (ctx, props) => {
      return Math.min(ctx.viewportWidth, ctx.viewportHeight) / 600;
    },
    aspect: ctx => ctx.viewportWidth > ctx.viewportHeight
      ? [ctx.viewportHeight / ctx.viewportWidth, 1]
      : [1, ctx.viewportWidth / ctx.viewportHeight],
  },

  blend: {
    enable: true,
    func: {
      srcRGB: 'src alpha',
      srcAlpha: 1,
      dstRGB: 1,
      dstAlpha: 1
    }
  },

  depth: {enable: true}
});

let xy = [];

const yShift = Math.sin(Math.PI / 3);
const unit = [[0, 0], [1 - Math.cos(Math.PI / 3), Math.sin(Math.PI / 3)]]
let c = 0;
const t = [];
const rows = 20 * extent;
const cols = 11 * extent;

for (let k = -cols; k <=cols; k++) {
  for (let j of [-1, 1]) {
    for (let i = -rows; i <= rows; i++) {
      const pt = unit.map(([x, y]) => [
        x + j * 0.75 + k * 3 - 0.25,
        (y + i * yShift * 2) * j - yShift * 0.5
          - j * yShift * 0.5,
        -1,
      ]);

      if (Math.hypot(pt[0][0], pt[0][1]) > 36.0 * extent) continue;
      xy.push(pt);
    }
  }
}

for (let j = rows; j >= -rows; j--) {
  const x1 = cols * 3 + 1.25;
  const e = 0.5;
  const shift = 1.5;
  const dx = -0.25;
  const dy = -yShift * 0.25;
  const ext = 2 * cols + 1;
  xy.push([
    [x1 + dx, j + dy, ext],
    [-x1 - e + dx, j + dy, 0],
    [-x1 - e + dx + shift, j - 0.5 + dy, 0],
    [x1 + dx + shift, j - 0.5 + dy, ext]
  ].map(([x, y, z]) => [
    x,
    (y + 0.25) * yShift * 2,
    z
  ]));
}

// Center it about zero
xy = xy.flat();
xy.reverse();

// Set up the data to be drawn. Note that we preallocate buffers and don't create
// them on every draw call.
const lineData = {
  roundResolution: 1,
  join: 'bevel',
  vertexCount: xy.length,
  vertexAttributes: {
    xy: regl.buffer(xy),
  }
};



const colors = [
  [1, 0.5, 0],
  [0, 0.5, 1],
  [0.5, 1, 0],
];
regl.frame(({time}) => {
  //const time = 1.0 * Math.PI / 180 / 0.1;
  regl.poll();
  regl.clear({color: [0.2, 0.2, 0.2, 1]});
  [0, 0.1].forEach((rate, i) => {
    regl.clear({depth: 1});
    drawLines({
      ...lineData,
      transform: mat2rotate([], mat2create(), time * rate),
      color: colors[i % colors.length]
    })
  });
});
